home *** CD-ROM | disk | FTP | other *** search
/ Black Crawling Systems Archive Release 1.0 / Black Crawling Systems Archive Release 1.0 (L0pht Heavy Industries, Inc.)(1997).ISO / advisories / GETOPT.TXT < prev    next >
Text File  |  1997-07-17  |  6KB  |  175 lines

  1.                        L0pht Security Advisory
  2.                     Advisory released Jan 27 1997
  3.  
  4.           Application: Solaris libc getopt(3) 
  5.  
  6.              Vulnerability Scope: Solaris 2.5 distributions
  7.  
  8.           Severity: Non-priveledged users can exploit a vulnerability
  9.              in the getopt(3) routine inside libc. As most SUID programs
  10.              in Solaris are dynamically linked, users can gain root
  11.              priveledges.
  12.  
  13.                       Author: mudge@l0pht.com
  14.  
  15. Overview:
  16.  
  17. A buffer overflow condition exists in the getopt(3) routine. By supplying
  18. an invalid option and replacing argv[0] of a SUID program that uses the
  19. getopt(3) function with the appropriate address and machine code instructions,
  20. it is possible to overwrite the saved stack frame and upon return(s) force
  21. the processor to execute user supplied instructions with elevated permissions.
  22.  
  23.  
  24. Description:
  25.  
  26. While evaluating programs in the Solaris Operating System environment 
  27. it became apparent that changing many programs trust argv[0] to never
  28. exceed a certain length. In addition it seemed as though getopt was
  29. simply copying argv[0] into a fixed size character array.
  30.  
  31.   ./test >>& ccc
  32.   Illegal instruction (core dumped)
  33.  
  34. Knowing that the code in ./test was overflow free it seemed that the problem
  35. must exist in one of the functions dynamically linked in at runtime through
  36. ld.so. A quick gander through the namelist showed a very limited range of
  37. choices for the problem to exist in.
  38.  
  39.   00020890 B _end
  40.   0002088c B _environ
  41.   00010782 R _etext
  42.            U _exit
  43.   00010760 ? _fini
  44.   0001074c ? _init
  45.   00010778 R _lib_version
  46.   000105ac T _start
  47.            U atexit
  48.   0002088c W environ
  49.            U exit
  50.   0001067c t fini_dummy
  51.   0002087c d force_to_data
  52.   0002087c d force_to_data
  53.   000106e4 t gcc2_compiled.
  54.   00010620 t gcc2_compiled.
  55.            U getopt
  56.   00010740 t init_dummy
  57.   00010688 T main
  58.  
  59. Next we checked out getopt() - as it looked like the most likely
  60. suspect.
  61.  
  62.   #include <stdio.h>
  63.  
  64.   main(int argc, char **argv)
  65.   {
  66.     int opt;
  67.  
  68.     while ((opt = getopt(argc, argv, "a")) != EOF) {
  69.       switch (opt) {
  70.       }
  71.     }
  72.   }
  73.  
  74.   >gcc -o test test.c
  75.   >./test -z
  76.   ./test: illegal option -- z
  77.  
  78. Note the name it threw back at the beggining of the error message. It was
  79. quite obvious that they are just yanking argv[0]. Changing argv[0] in 
  80. the test program confirms this.
  81.  
  82.   for (i=0; i< 4096; i++)
  83.     buffer[i] = 0x41;
  84.  
  85.    argv[0] = buffer;
  86.  
  87. With the above in place we see the following result:
  88.   >./test -z
  89.   [lot's of A's removed]AAAAAAAAA: illegal option -- z
  90.   Bus error (core dumped)
  91.  
  92. By yanking out the object file from the static archive libc that is supplied
  93. with Solaris our culprit was spotted [note - we assumed that libc.a was
  94. built from the same code base that libc.so was].
  95.  
  96.   > nm getopt.o
  97.            U _dgettext
  98.   00000000 T _getopt
  99.   00000000 D _sp
  100.            U _write
  101.   00000000 W getopt
  102.            U optarg
  103.            U opterr
  104.            U optind
  105.            U optopt
  106.            U sprintf
  107.            U strchr
  108.            U strcmp
  109.            U strlen
  110.  
  111. Here we see one of the infamous non-bounds-checking routines: sprintf();
  112. More than likely the code inside getopt.c looks something like the following:
  113.  
  114.   getopt.c:
  115.     char opterr[SOMESIZE];
  116.     ...
  117.     sprintf(opterr, argv[0]...);
  118.  
  119. Thus, whenever you pass in a non-existant option to a program that uses getopt
  120. you run into the potential problem with trusting that argv[0] is smaller
  121. than the space that has been allocated for opterr[]. 
  122.  
  123. This is interesting on the Sparc architecture as getopt() is usually called
  124. out of main() and you need two returns [note - there are certain situations
  125. in code on Sparc architectures that allow you to switch execution to your 
  126. own code without needing two returns. Take a look at the TBR for some
  127. enjoyable hacking] due to the sliding register windows. Some quick analysis
  128. of SUID programs on a standard Solaris 2.5 box show that most of these
  129. programs exit() or more likely call some form of usage()-exit() in the
  130. default case for getopt and thus are not exploitable. However, at least
  131. two of these programs provide the necessary returns to throw your
  132. address into the PC :
  133.      passwd(1)
  134.      login(1)
  135.  
  136. On Solaris X86 you do not need these double returns and thus a whole world of
  137. SUID programs allow unpriveledged users to gain root access: 
  138.     (list of programs vulnerable too big to put here. sigh.)
  139.  
  140. Exploit:
  141.  
  142.  
  143.   $./exploit "/bin/passwd" 4375 2> foo
  144.   # id
  145.   uid=0(root) gid=1(other)
  146.  
  147.   [ note: the source code for the exploit will be made available on the
  148.     www.l0pht.com/advisories.html page in a couple of days. Hey, we have
  149.     day jobs and sometimes spare time is impossible to come by. ]
  150.   
  151. Fixes:
  152.   For those with source:
  153.   If you are one of the few people who have a source code license the fix
  154.   should be fairly simple. Replace the sprintf() routine in getopt.c with
  155.   snprintf() and rebuld libc.
  156.  
  157.   Super Ugly kludge fix:
  158.   If you don't have the source code available (like most of us), one solution
  159.   is to use adb to change the name for getopt with something like getopz, 
  160.   yank a publicly available getopt.c, and put it in place of getopt. 
  161.   If anyone can tell me how to yank the object files out of dynamically
  162.   linked libraries it would be appreciated as you suffer performance
  163.   hits among larger problems by doing this from the static library Sun
  164.   provides as, of course, it is not PIC code. 
  165.   
  166. Thanks:
  167.   Special thanks go out to ][ceman for his co-work on this project. 
  168.  
  169. mudge@l0pht.com
  170.  
  171. ---
  172. Check out http://www.l0pht.com/advisories.html for other l0pht advisories
  173. ---
  174.  
  175.